/*=========================================================================
UberSim Source Code Release
-------------------------------------------------------------------------
Copyright (C) 2002 Manuela Veloso, Brett Browning, Mike Bowling,
                   James Bruce; {mmv, brettb, mhb, jbruce}@cs.cmu.edu
                   Erick Tryzelaar {erickt}@andrew.cmu.edu
School of Computer Science, Carnegie Mellon University
-------------------------------------------------------------------------
This software is distributed under the GNU General Public License,
version 2.  If you do not have a copy of this licence, visit
www.gnu.org, or write: Free Software Foundation, 59 Temple Place,
Suite 330 Boston, MA 02111-1307 USA.  This program is distributed
in the hope that it will be useful, but WITHOUT ANY WARRANTY,
including MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-------------------------------------------------------------------------*/

#include "mmgr.h"

#include "Math.h"
#include "Surface.h"

Surface::Surface ()
{
	surfaceParameters.mode       = 0;
	surfaceParameters.mu         = 0;
	surfaceParameters.mu2        = 0;
	surfaceParameters.bounce     = dInfinity;
	surfaceParameters.bounce_vel = dInfinity;
	surfaceParameters.soft_erp   = dInfinity;
	surfaceParameters.soft_cfm   = dInfinity;
	surfaceParameters.motion1    = dInfinity;
	surfaceParameters.motion2    = dInfinity;
	surfaceParameters.slip1      = 0;
	surfaceParameters.slip2      = 0;

	frictionDirection = Vector3::ZERO;
}

Surface::Surface (const dSurfaceParameters& surfaceParameters)
{
	this->surfaceParameters = surfaceParameters;
}

Surface::~Surface ()
{
}

dSurfaceParameters& Surface::getSurfaceParameters ()
{
	return surfaceParameters;
}

Vector3& Surface::getFrictionDirection ()
{
	return frictionDirection;
}

void Surface::setSurfaceParameters (const dSurfaceParameters& surfaceParameters)
{
	this->surfaceParameters = surfaceParameters;
}

void Surface::setFrictionDirection (const Vector3& frictionDirection)
{
	this->frictionDirection = frictionDirection;
}

Surface& Surface::operator += (const Surface& surface)
{
	if (surfaceParameters.mode != 0 && surface.surfaceParameters.mode != 0)
	{	
		surfaceParameters.mode |= surface.surfaceParameters.mode;

		surfaceParameters.mu2        = Math::max (surfaceParameters.mu2,        surface.surfaceParameters.mu2);
		surfaceParameters.bounce     = Math::min (surfaceParameters.bounce,     surface.surfaceParameters.bounce);
		surfaceParameters.bounce_vel = Math::min (surfaceParameters.bounce_vel, surface.surfaceParameters.bounce_vel);
		surfaceParameters.soft_erp   = Math::min (surfaceParameters.soft_erp,   surface.surfaceParameters.soft_erp);
		surfaceParameters.soft_cfm   = Math::min (surfaceParameters.soft_cfm,   surface.surfaceParameters.soft_cfm);
		surfaceParameters.motion1    = Math::min (surfaceParameters.motion1,    surface.surfaceParameters.motion1);		
		surfaceParameters.motion2    = Math::min (surfaceParameters.motion2,    surface.surfaceParameters.motion2);
		surfaceParameters.slip1      = Math::max (surfaceParameters.slip1,      surface.surfaceParameters.slip1);
		surfaceParameters.slip2      = Math::max (surfaceParameters.slip2,      surface.surfaceParameters.slip2);
	}
	else if (surface.surfaceParameters.mode != 0)
	{
		surfaceParameters = surface.surfaceParameters;
	}
	
	surfaceParameters.mu = Math::max (surfaceParameters.mu, surface.surfaceParameters.mu);
	
	return *this;
}

Surface Surface::operator + (const Surface& surface)
{
	Surface s;
	dSurfaceParameters& sp = s.getSurfaceParameters ();

	if (surfaceParameters.mode != 0 && surface.surfaceParameters.mode != 0)
	{	
		sp.mode = surfaceParameters.mode | surface.surfaceParameters.mode;

		sp.mu2        = Math::max (surfaceParameters.mu2,        surface.surfaceParameters.mu2);
		sp.bounce     = Math::min (surfaceParameters.bounce,     surface.surfaceParameters.bounce);
		sp.bounce_vel = Math::min (surfaceParameters.bounce_vel, surface.surfaceParameters.bounce_vel);
		sp.soft_erp   = Math::min (surfaceParameters.soft_erp,   surface.surfaceParameters.soft_erp);
		sp.soft_cfm   = Math::min (surfaceParameters.soft_cfm,   surface.surfaceParameters.soft_cfm);
		sp.motion1    = Math::min (surfaceParameters.motion1,    surface.surfaceParameters.motion1);		
		sp.motion2    = Math::min (surfaceParameters.motion2,    surface.surfaceParameters.motion2);
		sp.slip1      = Math::max (surfaceParameters.slip1,      surface.surfaceParameters.slip1);
		sp.slip2      = Math::max (surfaceParameters.slip2,      surface.surfaceParameters.slip2);
	}
	else if (surfaceParameters.mode != 0)
	{
		s.setSurfaceParameters (surfaceParameters);
	}
	else if (surface.surfaceParameters.mode != 0)
	{
		s.setSurfaceParameters (surface.surfaceParameters);
	}
	
	sp.mu = Math::max (surfaceParameters.mu, surface.surfaceParameters.mu);
	
	return s;
}
